
KMG.BackgroundPlaneObject = function ( context, config ) {

	KMG.BaseObject.call( this );
	var scope = this;
	this.config = config;
	this.context = context;

	this.geometry = new THREE.SphereGeometry( 500, 20, 10 );
	this.geometry.computeTangents();
	this.material = new THREE.MeshBasicMaterial({
		color: 0x00ff00,
		side: THREE.DoubleSide,
		depthTest: false,
		depthWrite: false,
		//wireframe: true
	});
	this.mesh = new THREE.Mesh( this.geometry, this.material );
	this.add(this.mesh);

	this.update = function()
	{

	};

};
KMG.BackgroundPlaneObject.prototype = Object.create( KMG.BaseObject.prototype );


KMG.PlaneGridObject = function ( context, config ) {

	KMG.BaseObject.call( this );
	var scope = this;
	this.config = config;
	this.context = context;

	this.createGridBkgGeometry = function()
	{
		var geometry = new THREE.PlaneGeometry( 10000, 10000, 2, 2 );
		geometry.computeFaceNormals();
		var material = new THREE.MeshPhongMaterial({
			ambient	: 0x444444,
			color: 0x0000ff,
			specular: 0xC0C0C0,
			shininess: 150,
			shading	: THREE.SmoothShading,
			side: THREE.DoubleSide,
			depthTest: false,
			depthWrite: false,
			//wireframe: true
		});
		var mesh = new THREE.Mesh( geometry, material );
		this.add(mesh);
	}
	this.createGridGeometry = function()
	{
		var geometry = new THREE.Geometry( );
		for (var i = 0; i <= 100; i++) {
			var p1 = new THREE.Vector3(-5000, i * 100 - 5000, 0);
			var p2 = new THREE.Vector3(5000, i * 100 - 5000, 0);
			geometry.vertices.push(p1);
			geometry.vertices.push(p2);

			var p3 = new THREE.Vector3(i * 100 - 5000, -5000, 0);
			var p4 = new THREE.Vector3(i * 100 - 5000, 5000, 0);
			geometry.vertices.push(p3);
			geometry.vertices.push(p4);
		}
		geometry.computeFaceNormals();
		var material = new THREE.LineBasicMaterial({
			color: 0x000030,
			linewidth: 5,
			opacity: 1.0,
			side: THREE.FrontSide,
			depthTest: false,
			depthWrite: false,
		});
		var line = new THREE.Line( geometry, material, THREE.LinePieces );
		this.add(line);
	}
	this.createGridGeometry();
	this.createGridBkgGeometry();

	this.update = function()
	{

	};

};
KMG.PlaneGridObject.prototype = Object.create( KMG.BaseObject.prototype );


KMG.PlaneSurfaceObject = function ( context, config ) {

	KMG.BaseObject.call( this );
	var scope = this;
	this.config = config;
	this.context = context;

	//this.geometry = new THREE.PlaneGeometry( 1000, 1000, 20, 10 );
	this.geometry = new THREE.SphereGeometry( 500, 20, 10 );
	this.material = new THREE.MeshPhongMaterial({
		ambient	: 0x444444,
		color: 0x0000ff,
		specular: 0xC0C0C0,
		shininess: 150,
		shading	: THREE.SmoothShading,
		side: THREE.DoubleSide,
		depthTest: false,
		depthWrite: false,
		//wireframe: true
	});
	this.mesh = new THREE.Mesh( this.geometry, this.material );
	this.add(this.mesh);

	this.update = function()
	{

	};

};
KMG.PlaneSurfaceObject.prototype = Object.create( KMG.BaseObject.prototype );


KMG.PlaneMapObject = function ( context, config ) {

	KMG.BaseObject.call( this );
	var scope = this;
	this.config = config;
	this.context = context;

	this.createShapes = function(coords, regionShapes, lineCoords)
	{
		var regionPoints = [];
		for (var i = 0; i < coords.length; i++) {
			var point = new THREE.Vector3( 10*coords[i][0], 10*coords[i][1], 0 );
			regionPoints.push( point );
		}
		var regionShape = new THREE.Shape(regionPoints);
		regionShapes.push(regionShape);

		for (var i = 1; i < regionPoints.length; i++) {
			lineCoords.push( regionPoints[i - 1] );
			lineCoords.push( regionPoints[i] );
		}
	};

	this.createLineShapes = function(coords, lineCoords)
	{
		var regionPoints = [];
		for (var i = 0; i < coords.length; i++) {
			var point = new THREE.Vector3( 10*coords[i][0], 10*coords[i][1], 0 );
			regionPoints.push( point );
		}
		for (var i = 1; i < regionPoints.length; i++) {
			lineCoords.push( regionPoints[i - 1] );
			lineCoords.push( regionPoints[i] );
		}
	}

	this.createBaseGeometry = function(coords)
	{
		var points = [];
		for (var n = 0; n < coords.length; n++) {
			points.push( new THREE.Vector3( 10*coords[n][0], 10*coords[n][1], 0 ) );
		}
		var shape = new THREE.Shape(points);

		var regionMaterial = new THREE.MeshPhongMaterial({
			ambient	: 0x000000,
			color: 0X0560d2,
			specular: 0Xffffff,
			shininess: 150,
			shading	: THREE.SmoothShading,
			side: THREE.FrontSide,
			depthTest: false,
			depthWrite: false,
			transparent: true,
		});
		var regionGeometry = new THREE.ShapeGeometry(shape);
		regionGeometry.computeCentroids();
		regionGeometry.computeFaceNormals();
		regionGeometry.computeMorphNormals();
		var mesh = new THREE.Mesh( regionGeometry, regionMaterial );
		this.add(mesh);


		var meshLine = new MeshLine();
		var lineGeometry = new THREE.ShapeGeometry(shape);
		meshLine.setGeometry( lineGeometry );

		var resolution = new THREE.Vector2( window.innerWidth, window.innerHeight );
		var lineMaterial = new MeshLineMaterial( {
			useMap: false,
			useAlphaMap: false,
			color: new THREE.Color( 0X6097ff ),
			opacity: 0.5,
			resolution: resolution,
			sizeAttenuation: !false,
			lineWidth: 3,
			near: this.context.mainCamera.near,
			far: this.context.mainCamera.far,
			depthTest: false,
			depthWrite: false,
			transparent: true,
			//blending: THREE.AdditiveBlending,
		});
		var mesh = new THREE.Mesh( meshLine.geometry, lineMaterial );
		this.context.effectScene.add( mesh );

		var lineMaterial = new THREE.LineBasicMaterial({
			color: 0X6097ff,
			linewidth: 3,
			side: THREE.FrontSide,
			depthTest: false,
			depthWrite: false,
		});
		var lineGeometry = new THREE.ShapeGeometry(shape);
		var line = new THREE.Line( lineGeometry, lineMaterial );
		this.add(line);
	};

	this.createExtrudeGeometry = function(coords)
	{
		var points = [];
		for (var i = 0; i < coords.length; i++) {
			points.push( new THREE.Vector2( 10*coords[i][0], 10*coords[i][1] ) );
		}
		var shape = new THREE.Shape(points);

		var regionMaterial = new THREE.MeshBasicMaterial({
			color: 0X0158c1,
			side: THREE.FrontSide,
			depthTest: false,
			depthWrite: false,
		});

		var simpleShapes = shape.toShapes(true);
		for (j = 0; j < simpleShapes.length; ++j) {
			var regionGeometry3d = simpleShapes[j].extrude({
				amount: 10,
				bevelEnabled: false
			});
			var mesh = new THREE.Mesh( regionGeometry3d, regionMaterial );
			this.add(mesh);
		}


		var lineMaterial = new THREE.LineBasicMaterial({
			color: 0X6097ff,
			linewidth: 3,
			side: THREE.FrontSide,
			depthTest: false,
			depthWrite: false,
		});
		var lineGeometry = new THREE.ShapeGeometry(shape);
		var line = new THREE.Line( lineGeometry, lineMaterial );
		this.add(line);
	};

	var worldContent = null;;
	var xhrWorld = new XMLHttpRequest();
	xhrWorld.timeout = 0;
	xhrWorld.withCredentials = false;
	xhrWorld.responseType = "";
	xhrWorld.onload = function() {
		worldContent = JSON.parse(this.response);
	}
	xhrWorld.open("GET", "world.json", false);
	xhrWorld.send(null);

	var chinaContent = null;;
	var chinaWorld = new XMLHttpRequest();
	chinaWorld.timeout = 0;
	chinaWorld.withCredentials = false;
	chinaWorld.responseType = "";
	chinaWorld.onload = function() {
		chinaContent = JSON.parse(this.response);
	}
	chinaWorld.open("GET", "chinaline.geojson", false);
	chinaWorld.send(null);

	if (worldContent != null && chinaWorld != null) {
		var regionShapes = [];
		var lineCoords = [];
		var worldFeatures = worldContent.features;
		for (var i = 0; i < worldFeatures.length; i++) {
			var geometry = worldFeatures[i].geometry;
			var rings = geometry.coordinates;
			if (rings.length > 0) {
				for (var j = 0; j < rings.length; j++) {
					var ring = rings[j];
					if (ring.length > 0) {
						var coords = ring[0];
						var coord = coords[0];
						if (coord instanceof Array) {
							for (var k = 0; k < ring.length; k++) {
								//this.createBaseGeometry(ring[k]);
								this.createShapes(ring[k], regionShapes, lineCoords);
							}
						} else {
							//this.createBaseGeometry(ring);
							this.createShapes(ring, regionShapes, lineCoords);
						}
					}
				}
			}
		}

		var chinaFeatures = chinaContent.features;
		for (var i = 0; i < chinaFeatures.length; i++) {
			var geometry = chinaFeatures[i].geometry;
			var ring = geometry.coordinates;
			if (ring.length > 0) {
				this.createLineShapes(ring, lineCoords);
			}
		}

		var regionMaterial = new THREE.MeshBasicMaterial({
			ambient	: 0x000000,
			color: 0X032237,
			specular: 0Xffffff,
			shininess: 150,
			shading	: THREE.SmoothShading,
			side: THREE.FrontSide,
			depthTest: false,
			depthWrite: false,
		});
		var regionGeometry = new THREE.ShapeGeometry(regionShapes);
		var regionMesh = new THREE.Mesh( regionGeometry, regionMaterial );

		var lineMaterial = new THREE.LineBasicMaterial({
			color: 0X1c3048,
			linewidth: 1,
			side: THREE.FrontSide,
			depthTest: false,
			depthWrite: false,
		});
		var lineShape = new THREE.Shape(lineCoords);
		var lineGeometry = new THREE.ShapeGeometry(lineShape);
		var lineMesh = new THREE.Line( lineGeometry, lineMaterial, THREE.LinePieces );

		this.add(lineMesh);
		this.add(regionMesh);
	}

	this.update = function()
	{

	};

};
KMG.PlaneMapObject.prototype = Object.create( KMG.BaseObject.prototype );


KMG.PlaneTrailObject = function ( context, config ) {

	KMG.BaseObject.call( this );
	var scope = this;
	this.config = config;
	this.context = context;

	this.addLineGeometry = function(start, end, value)
	{
		var geometry = makeConnectionLineGeometry( start, end, value, 100, 1 );

		var meshLine = new MeshLine();
		meshLine.setGeometry( geometry );

		var resolution = new THREE.Vector2( window.innerWidth, window.innerHeight );
		var lineMaterial = new MeshLineMaterial( {
			useMap: false,
			useAlphaMap: false,
			color: new THREE.Color( 0xffffff ),
			opacity: 0.1,
			resolution: resolution,
			sizeAttenuation: false,
			lineWidth: 5,
			near: this.context.mainCamera.near,
			far: this.context.mainCamera.far,
			depthTest: false,
			depthWrite: false,
			transparent: true,
			//blending: THREE.AdditiveBlending,
		});
		var mesh = new THREE.Mesh( meshLine.geometry, lineMaterial );
		this.add(mesh);

		/*
		var geometry = makeConnectionLineGeometry( start, end, value, 100, 1 );

		var lineMaterial = new THREE.LineBasicMaterial({
			color: 0Xffffff,
			linewidth: 3,
			side: THREE.FrontSide,
			depthTest: false,
			depthWrite: false,
			blending: THREE.AdditiveBlending,
		});
		var line = new THREE.Line( geometry, lineMaterial );
		//this.add(line);
		this.context.effectScene.add(line);
		*/
	};

	this.update = function()
	{

	};

	this.addStation = function()
	{
		var locations = window.data.locations;
		for (var i = 1; i < locations.length; i++) {
			var location = locations[i];
			this.addLineGeometry( new THREE.Vector3(location.planet_v, location.planet_u, 0), new THREE.Vector3(116, 39, 0), 3000 );
		}
	};
	this.addStation();

	//this.addGeometry( new THREE.Vector3(0, 0, 0), new THREE.Vector3(116, 39, 0), 3000 );

};
KMG.PlaneTrailObject.prototype = Object.create( KMG.BaseObject.prototype );


KMG.PlaneLineTrailObject = function ( context, config ) {

	KMG.BaseObject.call( this );
	var scope = this;
	this.config = config;
	this.context = context;

	this.lineMaterials = [];

	this.addGeometry = function(start, end, value)
	{
		var points = makeConnectionLinePoints( start, end, value, 100, 1 );

		var times = [];
		var pointSize = points.length;
		var sumTime = 1000;
		var detaTile = sumTime / pointSize;
		for (var i = 0; i < pointSize; i++) {
			times.push(i*detaTile);
		}

		var geometry = new THREE.Geometry();
		for( var i = 0; i < points.length; i ++ ) {
			geometry.vertices.push( points[i] );
		}
		geometry.size = points.size;

		var meshLine = new StreamMeshLine();
		meshLine.setGeometry( geometry, times );

		var resolution = new THREE.Vector2( window.innerWidth, window.innerHeight );
		var lineMaterial = new THREE.StreamMeshLineMaterial( {
			vertexShader: THREE.CycleStreamMeshLineShader.vertexShader,
			fragmentShader: THREE.CycleStreamMeshLineShader.fragmentShader,
			useMap: false,
			useAlphaMap: false,
			color: new THREE.Color( 0x9df4fd ),
			opacity: 1,
			transparent: true,
			resolution: resolution,
			sizeAttenuation: false,
			lineWidth: 5,
			near: this.context.mainCamera.near,
			far: this.context.mainCamera.far,
			invertType: 0,
			sycleType: 0,
			sumTime: sumTime,
			sycleTime: 2 * sumTime,
			traceTime: sumTime / 2,
			currentTime: 10000000.0,
			depthTest: false,
			depthWrite: false,
			blending: THREE.AdditiveBlending,
		});
		this.lineMaterials.push(lineMaterial);

		var mesh = new THREE.Mesh( meshLine.geometry, lineMaterial );
		this.add(mesh);
	};

	this.invertType = 0;
	this.currentTime = 0;
	this.update = function()
	{
		if (this.currentTime % 2000 == 0) {
			if (this.invertType == 1) {
				this.invertType = 0;
			} else {
				this.invertType = 1;
			}
		}
		this.currentTime += 20.0;

		var resolution = new THREE.Vector2( window.innerWidth, window.innerHeight );
		var near = this.context.mainCamera.near;
		var far = this.context.mainCamera.far;

		for (var i = 0; i < this.lineMaterials.length; i++) {
			var lineMaterial = this.lineMaterials[i];
			lineMaterial.resolution = resolution;
			lineMaterial.near = near;
			lineMaterial.far = far;
			var invertType = lineMaterial.uniforms.invertType;
			var currentTime = lineMaterial.uniforms.currentTime;
			if (currentTime != null) {
				invertType.value = this.invertType;
				currentTime.value = this.currentTime;
			}
		}
	};

	this.addStation = function()
	{
		var locations = window.data.locations;
		for (var i = 1; i < locations.length; i++) {
			var location = locations[i];
			this.addGeometry( new THREE.Vector3(location.planet_v, location.planet_u, 0), new THREE.Vector3(116, 39, 0), 3000 );
		}
	};
	this.addStation();

	//this.addGeometry( new THREE.Vector3(0, 0, 0), new THREE.Vector3(116, 39, 0), 3000 );

};
KMG.PlaneLineTrailObject.prototype = Object.create( KMG.BaseObject.prototype );


KMG.PlaneStationObject = function ( context, config ) {

	KMG.BaseObject.call( this );
	var scope = this;
	this.config = config;
	this.context = context;

	function textures (lineName) {

		var canvas = document.createElement( 'canvas' );
		var ctx = canvas.getContext( '2d' );

		canvas.width = 64;
		canvas.height = 64;

		ctx.fillStyle = '#000000';
		ctx.fillRect(0, 0, 64, 64);
		ctx.fillStyle = '#fff';
		ctx.strokeStyle = '#fff';
		ctx.font = "10px sans-serif";
		ctx.textBaseline = 'hanging';
		//ctx.textAlign = 'center';
		ctx.fillText(lineName , 0, 0);
		ctx.globalAlpha = 0.0;


		var canvasTexture = new THREE.Texture(canvas);
		canvasTexture.wrapS = THREE.ClampToEdgeWrapping;
		canvasTexture.wrapT = THREE.ClampToEdgeWrapping;
		canvasTexture.minFilter = THREE.NearestFilter;
		canvasTexture.minFilter = THREE.NearestFilter;
		canvasTexture.needsUpdate = true;

		return canvasTexture;
	}

	function CreatePoint(texture,size,color)
	{
		var particlesGeo =  new THREE.Geometry();
		particlesGeo.dynamic = true;

		var shaderMaterial = new THREE.ParticleSystemMaterial( {
			size: 64,
			map: texture,
			blending: 		THREE.AdditiveBlending,
			depthTest: 	false,
			depthWrite: 	false,
			transparent:	true,
			sizeAttenuation: false,
		});

		particlesGeo.vertices.push( new THREE.Vector3(0,0,0.0) );

		var pSystem = new THREE.ParticleSystem( particlesGeo, shaderMaterial );
		pSystem.dynamic = true;
		pSystem.rotation.x += Math.PI;
		return pSystem;
	}

	this.addStaticPointGeometry = function(point, size)
	{
		var texture = THREE.ImageUtils.loadTexture( "img/static_station_32.png" );
		var material = new THREE.MeshBasicMaterial( {
			color: 0xffffff,
			map: texture,
			transparent: true,
		} );
		var geometry = new THREE.PlaneGeometry( size, size );
		var mesh = new THREE.Mesh( geometry, material );
		mesh.position = point;
		this.add( mesh );
	};

	this.dynamicPoints = [];
	this.addDynamicPointGeometry = function(point, size)
	{
		var paths = [];
		paths.push("img/dynamic_station_64_0.png");
		paths.push("img/dynamic_station_64_1.png");
		paths.push("img/dynamic_station_64_2.png");
		paths.push("img/dynamic_station_64_3.png");
		paths.push("img/dynamic_station_64_4.png");
		paths.push("img/dynamic_station_64_3.png");
		paths.push("img/dynamic_station_64_2.png");
		paths.push("img/dynamic_station_64_1.png");
		paths.push("img/dynamic_station_64_0.png");
		for (var i = 0; i < paths.length; i++) {
			var texture = THREE.ImageUtils.loadTexture( paths[i] );
			var material = new THREE.MeshBasicMaterial( {
				color: 0xffffff,
				map: texture,
				transparent: true,
			} );
			var geometry = new THREE.PlaneGeometry( size, size );
			var mesh = new THREE.Mesh( geometry, material );
			mesh.position = point;
			mesh.visible = false;
			this.add( mesh );
			this.dynamicPoints.push(mesh);
		}
	};

	this.projectVector = function(worldVector)
	{
		var projector = new THREE.Projector();
		var vector = projector.projectVector(worldVector, this.context.mainCamera);
		var halfWidth = window.innerWidth / 2;
		var halfHeight = window.innerHeight / 2;
		var result = {
			x: Math.round(vector.x * halfWidth + halfWidth),
			y: Math.round(-vector.y * halfHeight + halfHeight)
		};
		return result;
	}

	this.dynamicDeta = 0;
	this.dynamicIndex = 0;
	this.update = function()
	{
		var dynamicIndex = this.dynamicIndex % this.dynamicPoints.length;
		for (var i = 0; i < this.dynamicPoints.length; i++) {
			this.dynamicPoints[i].visible = (i == dynamicIndex);
		}
		if (this.dynamicDeta % 5 == 0) {
			this.dynamicIndex += 1;
		}
		this.dynamicDeta += 1;

		for (var i = 0; i < this.textObjects.length; i++) {
			var pos = this.textObjects[i].pos;
			var textObj = this.textObjects[i].obj;

			var p0 =  this.projectVector(new THREE.Vector3(pos.x, pos.y, pos.z));
			var p1 =  this.projectVector(new THREE.Vector3(pos.x + 100, pos.y + 100, pos.z));
			var dx = 100.0 / Math.abs(p1.x - p0.x);
			var dy = 100.0 / Math.abs(p1.y - p0.y);

			textObj.position = new THREE.Vector3(pos.x + 40 * dx, pos.y - 32 * dx, 0);
		}
	};

	this.textObjects = [];
	this.addStation = function()
	{
		var locations = window.data.locations;
		for (var i = 1; i < locations.length; i++) {
			var location = locations[i];
			this.addStaticPointGeometry(new THREE.Vector3(10*location.planet_v, 10*location.planet_u, 0), 8);

			var textObj = CreatePoint(textures(location.name), 64.0, 0x00ff00);
			textObj.position = new THREE.Vector3(10*location.planet_v, 10*location.planet_u, 0);
			this.add( textObj );

			var text = {};
			text.obj = textObj;
			text.pos = new THREE.Vector3(10*location.planet_v, 10*location.planet_u, 0);
			this.textObjects.push(text);
		}

		this.addDynamicPointGeometry(new THREE.Vector3(10*116, 10*39, 0), 64);
	};
	this.addStation();

};
KMG.PlaneStationObject.prototype = Object.create( KMG.BaseObject.prototype );


KMG.PlaneEffectsComposer = function(context, renderer) {

	var renderTargetParameters = {
		minFilter: THREE.LinearFilter,
		magFilter: THREE.LinearFilter,
		format: THREE.RGBAFormat,
		stencilBuffer: false
	};

	THREE.EffectComposer.call( this, renderer );
	var scope = this;
	this.context = context;
	this.renderer = renderer;

	var baseRenderPass = new THREE.RenderPass( context.baseScene, context.baseCamera );
	baseRenderPass.clear = true;
	this.addPass( baseRenderPass );

	var mainRenderPass = new THREE.RenderPass( context.mainScene, context.mainCamera );
	mainRenderPass.clear = false;
	this.addPass( mainRenderPass );

	var effectMainRenderPass = new THREE.RenderPass( context.effectScene, context.mainCamera );
	effectMainRenderPass.clear = false;
	this.addPass( effectMainRenderPass );

	var effectMainFXAA = new THREE.ShaderPass( THREE.FXAAShader );
	this.addPass( effectMainFXAA );

	var effectMainHBlur = new THREE.ShaderPass( THREE.HorizontalBlurShader );
	this.addPass( effectMainHBlur );
	var effectMainVBlur = new THREE.ShaderPass( THREE.VerticalBlurShader );
	this.addPass( effectMainVBlur );

	var effectMainBloom = new THREE.BloomPass( 0.0 );
	this.addPass( effectMainBloom );

	var effectSave = new THREE.SavePass( new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, renderTargetParameters ) );
	effectSave.clear = false;
	this.addPass( effectSave );

	var clearDepthPass = new THREE.ClearDepthPass( );
	clearDepthPass.clear = false;
	this.addPass( clearDepthPass );

	var effectRenderPass = new THREE.RenderPass( context.effectScene, context.mainCamera );
	effectRenderPass.clear = true;
	effectRenderPass.clearAlpha = 0;
	effectRenderPass.clearColor = 0x000000;
	this.addPass( effectRenderPass );

	var depthPass = new THREE.DepthPass( );
	depthPass.clear = false;
	this.addPass( depthPass );

	var effectFXAA = new THREE.ShaderPass( THREE.FXAAShader );
	this.addPass( effectFXAA );

	var effectBloom = new THREE.BloomPass( 0.0 );
	this.addPass( effectBloom );

	var effectHBlur = new THREE.ShaderPass( THREE.HorizontalBlurShader );
	this.addPass( effectHBlur );
	var effectVBlur = new THREE.ShaderPass( THREE.VerticalBlurShader );
	this.addPass( effectVBlur );

	var effectBlend = new THREE.ShaderPass( THREE.MixTextureShader, "tDiffuse1" );
	effectBlend.uniforms[ 'opacity' ].value = 1.0;
	effectBlend.uniforms[ 'tDiffuse2' ].value = effectSave.renderTarget;
	effectBlend.renderToScreen = true;
	this.addPass( effectBlend );

	//var effectCopy = new THREE.ShaderPass( THREE.CopyShader );
	//effectCopy.renderToScreen = true;
	//this.addPass( effectCopy );

	this.effect = 1;
	this.opacity = 0;
	this.sender = null;
	this.callback = null;
	this.enterEffect = function(callback, sender) {
		this.effect = 1;
		this.opacity = 0;
		this.sender = sender;
		this.callback = callback;
	};
	this.exitEffect = function(callback, sender) {
		this.effect = 0;
		this.opacity = 1;
		this.sender = sender;
		this.callback = callback;
	};

	this.update = function() {
		if (this.effect == 0) {
			this.opacity -= 0.05;
			if (this.opacity < 0) {
				this.opacity = 0;
				if (this.callback != null) {
					this.callback(this.sender);
					this.sender = null;
					this.callback = null;
				}
			}
		} else {
			this.opacity += 0.05;
			if (this.opacity > 1) {
				this.opacity = 1;
				if (this.callback != null) {
					this.callback(this.sender);
					this.sender = null;
					this.callback = null;
				}
			}
		}

		var mainBlurAmount = 0.0;
		effectMainHBlur.uniforms[ 'h' ].value = mainBlurAmount / ( window.innerWidth / 2 );
		effectMainVBlur.uniforms[ 'v' ].value = mainBlurAmount / ( window.innerHeight / 2 );
		effectMainFXAA.uniforms["resolution"].value.x = 1 / window.innerWidth;
		effectMainFXAA.uniforms["resolution"].value.y = 1 / window.innerHeight;
		effectMainBloom.copyUniforms["opacity"].value = 0.0;

		var effectBlurAmount = 0.5;
		effectHBlur.uniforms[ 'h' ].value = effectBlurAmount / ( window.innerWidth / 2 );
		effectVBlur.uniforms[ 'v' ].value = effectBlurAmount / ( window.innerHeight / 2 );
		effectFXAA.uniforms["resolution"].value.x = 1 / window.innerWidth;
		effectFXAA.uniforms["resolution"].value.y = 1 / window.innerHeight;
		effectBloom.copyUniforms["opacity"].value = 1.0;

		effectBlend.uniforms[ 'opacity' ].value = this.opacity;
		effectBlend.uniforms[ 'tDiffuse2' ].value = effectSave.renderTarget;
	};

};
KMG.PlaneEffectsComposer.prototype = Object.create( THREE.EffectComposer.prototype );


KMG.PlaneScene = function ( domElement, config ) {

	var scope = this;
	this.config = config;
	this.domElement = ( domElement !== undefined ) ? domElement : document;
	this.visible = true;

	this.context = {
		container : null,
		composer : null,
		renderer : null,
		baseCamera : null,
		baseScene : null,
		mainCamera : null,
		mainScene : null,
		effectScene : null,
		containerWidth : 0,
		containerHeight : 0,
		objects : [],
	};

	this.enterScene = function(callback, sender)
	{
		scope.context.composer.enterEffect(callback, sender);
	};

	this.exitScene = function(callback, sender)
	{
		scope.context.composer.exitEffect(callback, sender);
	};

	this.isVisible = function()
	{
		return this.visible;
	};

	this.setVisible = function(visible)
	{
		this.visible = visible;
		this.context.controls.enabled = visible;
	};

	this.addObjectToBaseScene = function(object)
	{
		this.context.objects.push(object);
		this.context.baseScene.add(object);
	};

	this.addObjectToMainScene = function(object)
	{
		this.context.objects.push(object);
		this.context.mainScene.add(object);
	};

	this.addObjectToEffectScene = function(object)
	{
		this.context.objects.push(object);
		this.context.effectScene.add(object);
	};

	this.reset = function()
	{

	};

	this.start = function()
	{

	};

	this.stop = function()
	{

	};

	this.onSize = function()
	{
		this.context.containerWidth = window.innerWidth;
		this.context.containerHeight = window.innerHeight;

		this.context.baseCamera.aspect = window.innerWidth / window.innerHeight;
		this.context.baseCamera.updateProjectionMatrix();
		this.context.mainCamera.aspect = window.innerWidth / window.innerHeight;
		this.context.mainCamera.updateProjectionMatrix();

		this.context.renderer.setSize( window.innerWidth, window.innerHeight );
		this.context.composer.setSize(window.innerWidth, window.innerHeight);
	};

	this.onRender = function()
	{
		if (!this.visible) {
			return;
		}

		scope.context.containerWidth = window.innerWidth;
		scope.context.containerHeight = window.innerHeight;
		scope.context.controls.update();

		for (var i = 0; i < scope.context.objects.length; i++) {
			scope.context.objects[i].update();
		}

		scope.context.renderer.setClearColor( 0x001862, 1.0 );
		scope.context.renderer.clear(true, true, true);

		//scope.context.renderer.render(this.context.effectScene, this.context.mainCamera);
		scope.context.composer.render(0.1);
	};

	this.context.container = this.domElement;
	this.context.renderer = this.config.renderer;

	this.context.baseCamera = new THREE.PerspectiveCamera( this.config.camera.fieldOfView, window.innerWidth / window.innerHeight, this.config.camera.near, this.config.camera.far );
	this.context.baseCamera.position.z = 2000;
	var baseScene = new THREE.Scene();
	var baseAmbientLight = new THREE.AmbientLight( 0x888888 );
	baseScene.add( baseAmbientLight );
	var baseDirectional = new THREE.DirectionalLight( 0xFFFFFF, 2.0);
	baseDirectional.position.set( -1000000, -1000000, 1000000 );
	baseScene.add( baseDirectional );
	baseScene.updateMatrix();
	scope.context.baseScene = baseScene;
	//this.addObjectToBaseScene(new KMG.BackgroundPlaneObject(this.context, this.config));

	this.context.mainCamera = new THREE.PerspectiveCamera( this.config.camera.fieldOfView, window.innerWidth / window.innerHeight, this.config.camera.near, this.config.camera.far );
	this.context.mainCamera.position.z = 2000;
	var mainScene = new THREE.Scene();
	var mainAmbientLight = new THREE.AmbientLight( 0x888888 );
	//mainScene.add( mainAmbientLight );
	//var mainDirectional = new THREE.DirectionalLight( 0xFFFFFF, 2.0);
	//mainDirectional.position.set( -1000000, -1000000, 1000000 );
	var mainDirectional = new THREE.PointLight( 0x0000FF, 0.2, 1500000);
	mainDirectional.position.set( 0, 0, 1000000 );
	mainScene.add( mainDirectional );
	mainScene.updateMatrix();
	scope.context.mainScene = mainScene;

	var effectScene = new THREE.Scene();
	var effectAmbientLight = new THREE.AmbientLight( 0x888888 );
	//effectScene.add( effectAmbientLight );
	//var effectDirectional = new THREE.DirectionalLight( 0xFFFFFF, 2.0);
	//effectDirectional.position.set( -1000000, -1000000, 1000000 );
	var effectDirectional = new THREE.PointLight( 0xFFFFFF, 0.2, 1500000);
	effectDirectional.position.set( 0, 0, 1000000 );
	effectScene.add( effectDirectional );
	effectScene.updateMatrix();
	this.context.effectScene = effectScene;

	this.addObjectToEffectScene(new KMG.PlaneTrailObject(this.context, this.config));
	this.addObjectToMainScene(new KMG.PlaneMapObject(this.context, this.config));
	this.addObjectToMainScene(new KMG.PlaneGridObject(this.context, this.config));

	this.addObjectToMainScene(new KMG.PlaneStationObject(this.context, this.config));
	this.addObjectToEffectScene(new KMG.PlaneLineTrailObject(this.context, this.config));

	this.context.composer = new KMG.PlaneEffectsComposer(this.context, this.context.renderer);
	this.context.objects.push(this.context.composer);

	this.context.controls = new KMG.SceneControls( this.context.renderer.getContext(), this.context.mainCamera, this.context.container );
	this.context.controls.translate = new THREE.Vector3(10 * 108.95, 10 * 34.27, 0);
	this.context.controls.distance = 600;
	this.context.controls.update(true);

};